--- /dev/null
+/*
+
+ Implementation of special data used by Garmin products.
+
+ Copyright (C) 2006 Olaf Klein, o.b.klein@t-online.de
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "defs.h"
+#include "garmin_fs.h"
+#include "garmin_tables.h"
+#include "inifile.h"
+
+#define MYNAME "garmin_fs"
+
+garmin_fs_t *
+garmin_fs_alloc(const int protocol)
+{
+ garmin_fs_t *result = NULL;
+
+ result = (garmin_fs_t *)xcalloc(1, sizeof(*result));
+ result->fs.type = FS_GMSD;
+ result->fs.copy = (fs_copy) garmin_fs_copy;
+ result->fs.destroy = garmin_fs_destroy;
+ result->fs.next = NULL;
+
+ result->protocol = protocol;
+
+ return result;
+}
+
+void
+garmin_fs_destroy(void *fs)
+{
+ garmin_fs_t *data = (garmin_fs_t *) fs;
+ if (data != NULL)
+ {
+ garmin_ilink_t *ilinks;
+
+ if (data->city != NULL) xfree(data->city);
+ if (data->facility != NULL) xfree(data->facility);
+ if (data->state != NULL) xfree(data->state);
+ if (data->cc != NULL) xfree(data->cc);
+ if (data->cross_road != NULL) xfree(data->cross_road);
+ if ((ilinks = data->ilinks) != NULL) {
+ ilinks->ref_count--;
+ if (ilinks->ref_count <= 0) {
+ while (ilinks != NULL) {
+ garmin_ilink_t *tmp = ilinks;
+ ilinks = ilinks->next;
+ xfree(tmp);
+ }
+ }
+ }
+ xfree(data);
+ }
+}
+
+void garmin_fs_copy(garmin_fs_t **dest, garmin_fs_t *src)
+{
+ if (src == NULL)
+ {
+ *dest = NULL;
+ return;
+ }
+ *dest = (garmin_fs_t *) xmalloc(sizeof(*src));
+
+ /* do not copy interlinks, only increment the refrence counter */
+ if (src->ilinks != NULL) src->ilinks->ref_count++;
+
+ memcpy(*dest, src, sizeof(*src));
+
+ (*dest)->city = (src->city != NULL) ? xstrdup(src->city) : NULL;
+ (*dest)->facility = (src->facility != NULL) ? xstrdup(src->facility) : NULL;
+ (*dest)->state = (src->state != NULL) ? xstrdup(src->facility) : NULL;
+ (*dest)->cc = (src->cc != NULL) ? xstrdup(src->cc) : NULL;
+ (*dest)->cross_road = (src->cross_road != NULL) ? xstrdup(src->cross_road) : NULL;
+ (*dest)->addr = (src->addr != NULL) ? xstrdup(src->addr) : NULL;
+}
+
+/* GPX - out */
+
+void
+garmin_fs_xml_fprint(FILE *ofd, const waypoint *waypt)
+{
+ garmin_fs_t *gmsd = GMSD_FIND(waypt);
+ if (gmsd == NULL) return;
+
+ if ((gmsd->flags.category && gmsd->category) ||
+ gmsd->flags.depth ||
+ gmsd->flags.proximity ||
+ gmsd->flags.temperature ||
+ gmsd->flags.display)
+ {
+ int space = 1;
+
+ fprintf(ofd, "%*s<extensions>\n", space++ * 2, "");
+ fprintf(ofd, "%*s<gpxx:WaypointExtension xmlns:gpxx=\"" \
+ "http://www.garmin.com/xmlschemas/GpxExtensions/v2\" " \
+ "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
+ "xsi:schemaLocation=\"http://www.garmin.com/xmlschemas/GpxExtensions/v2 " \
+ "http://www.garmin.com/xmlschemas/GpxExtensions/v2/GpxExtensionsv2.xsd\">\n", space++ * 2, "");
+ if (gmsd->flags.proximity)
+ fprintf(ofd, "%*s<gpxx:Proximity>%.6f</gpxx:Proximity>\n", space * 2, "", gmsd->proximity);
+ if (gmsd->flags.temperature)
+ fprintf(ofd, "%*s<gpxx:Temperature>%.6f</gpxx:Temperature>\n", space * 2, "", gmsd->temperature);
+ if (gmsd->flags.depth)
+ fprintf(ofd, "%*s<gpxx:Depth>%.6f</gpxx:Depth>\n", space * 2, "", gmsd->depth);
+ if (gmsd->flags.display)
+ {
+ char *cx;
+ switch(gmsd->display)
+ {
+ case gt_display_mode_symbol:
+ cx = "SymbolOnly";
+ break;
+ case gt_display_mode_symbol_and_comment:
+ cx = "SymbolAndDescription";
+ break;
+ default:
+ cx = "SymbolAndName";
+ break;
+ }
+ fprintf(ofd, "%*s<gpxx:DisplayMode>%s</gpxx:DisplayMode>\n", space * 2, "", cx);
+ }
+ if (gmsd->flags.category && gmsd->category)
+ {
+ int i;
+ gbuint16 cx = gmsd->category;
+ fprintf(ofd, "%*s<gpxx:Categories>\n", space++ * 2, "");
+ for (i = 0; i < 16; i++)
+ {
+ if (cx & 1)
+ fprintf(ofd, "%*s<gpxx:Category>Category %d</gpxx:Category>\n", space*2, "", i+1);
+ cx = cx >> 1;
+ }
+ fprintf(ofd, "%*s</gpxx:Categories>\n", --space * 2, "");
+ }
+ fprintf(ofd, "%*s</gpxx:WaypointExtension>\n", --space * 2, "");
+ fprintf(ofd, "%*s</extensions>\n", --space * 2, "");
+ }
+
+}
+
+void
+garmin_fs_xml_convert(const int base_tag, int tag, const char *cdatastr, waypoint *waypt)
+{
+ garmin_fs_t *gmsd;
+
+ gmsd = GMSD_FIND(waypt);
+ if (gmsd == NULL) {
+ gmsd = garmin_fs_alloc(-1);
+ fs_chain_add(&waypt->fs, (format_specific_data *) gmsd);
+ }
+
+ tag -= base_tag;
+/*
+ tt_garmin_extension, -> 0
+ tt_garmin_waypt_extension, -> 1
+ tt_garmin_proximity, -> 2
+ tt_garmin_temperature,-> 3
+ tt_garmin_depth, -> 4
+ tt_garmin_display_mode, -> 5
+ tt_garmin_categories, -> 6
+ tt_garmin_category, -> 7
+*/
+ switch(tag) {
+ case 2: GMSD_SET(proximity, atof(cdatastr)); break;
+ case 3: GMSD_SET(temperature, atof(cdatastr)); break;
+ case 4: GMSD_SET(depth, atof(cdatastr)); break;
+ case 5: if (case_ignore_strcmp(cdatastr, "SymbolOnly") == 0) {
+ GMSD_SET(display, gt_display_mode_symbol);
+ }
+ else if (case_ignore_strcmp(cdatastr, "SymbolAndDescription") == 0) {
+ GMSD_SET(display, gt_display_mode_symbol_and_comment);
+ }
+ else {
+ GMSD_SET(display, gt_display_mode_symbol_and_name);
+ }
+ break;
+ case 7: if ( ! garmin_fs_merge_category(cdatastr, waypt)) {
+ warning(MYNAME ": Unable to convert category \"%s \"!\n", cdatastr);
+ }
+ break;
+ }
+}
+
+unsigned char
+garmin_fs_convert_category(const char *category_name, gbuint16 *category)
+{
+ int i;
+ int cat = 0;
+
+ if ((case_ignore_strncmp(category_name, "Category ", 9) == 0) &&
+ (1 == sscanf(category_name + 9, "%d", &i)) &&
+ (i >= 1) && (i <= 16)) {
+ cat = (1 << --i);
+ }
+ else if (global_opts.inifile != NULL) {
+ for (i = 0; i < 16; i++) {
+ char *c;
+ char key[3];
+
+ snprintf(key, sizeof(key), "%d", i + 1);
+ c = inifile_readstr(global_opts.inifile, GMSD_SECTION_CATEGORIES, key);
+ if ((c != NULL) && (case_ignore_strcmp(c, category_name) == 0)) {
+ cat = (1 << i);
+ break;
+ }
+ }
+ }
+ if (cat == 0) {
+ return 0;
+ }
+ else {
+ *category = cat;
+ return 1;
+ }
+}
+
+unsigned char
+garmin_fs_merge_category(const char *category_name, waypoint *waypt)
+{
+ gbuint16 cat;
+ garmin_fs_t *gmsd;
+
+ if (!garmin_fs_convert_category(category_name, &cat)) {
+ return 0;
+ }
+
+ gmsd = GMSD_FIND(waypt);
+ cat = cat | ( GMSD_GET(category, 0) );
+
+ if (gmsd == NULL) {
+ gmsd = garmin_fs_alloc(-1);
+ fs_chain_add(&waypt->fs, (format_specific_data *) gmsd);
+ }
+ GMSD_SET(category, cat);
+ return 1;
+}
--- /dev/null
+/*
+
+ Implementation of special data used by Garmin products.
+
+ Copyright (C) 2006 Olaf Klein, o.b.klein@t-online.de
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#ifndef GARMIN_FS_H
+#define GARMIN_FS_H
+
+#include <ctype.h>
+#include "defs.h"
+
+/* this order is used by most devices */
+/* typedef enum {
+ garmin_display_symbol_and_name = 0,
+ garmin_display_symbol_only = 1,
+ garmin_display_symbol_and_description = 2
+} garmin_display_t;
+*/
+
+/* macros */
+
+#define GMSD_FIND(a) (garmin_fs_t *) fs_chain_find((a)->fs, FS_GMSD)
+
+/* GMSD_GET(a,b): a = any gmsd field, b = default value */
+#define GMSD_GET(a,b) ((gmsd) && (gmsd->flags.a)) ? (gmsd->a) : (b)
+
+/* GMSD_SET(a,b): a = numeric gmsd field, b = numeric source */
+#define GMSD_SET(a,b) if (gmsd) {gmsd->a = (b); gmsd->flags.a = 1; }
+
+/* GMSD_SETSTR(a,b): a = gmsd field, b = null terminated source */
+#define GMSD_SETSTR(a,b) if (gmsd && (b) && (b)[0]) { gmsd->a = xstrdup((b)); gmsd->flags.a = 1; }
+
+/* GMSD_SETNSTR(a,b,c): a = gmsd field, b = source, c = sizeof(source) */
+#define GMSD_SETNSTR(a,b,c) if (gmsd && (b) && (b)[0]) { gmsd->a = xstrndup((b),(c)); gmsd->flags.a = 1; }
+
+/* GMSD_GETNSTR(a,b,c): a = gmsd field, b = target, c = sizeof(target) */
+#define GMSD_GETNSTR(a,b,c) if (gmsd && gmsd->flags.a) strncpy((b),gmsd->a,(c))
+
+typedef struct garmin_ilink_s {
+ int ref_count;
+ double lat, lon;
+ struct garmin_ilink_s *next;
+} garmin_ilink_t;
+
+typedef struct {
+ unsigned int icon:1;
+ unsigned int wpt_class:1;
+ unsigned int display:1;
+ unsigned int category:1;
+ unsigned int depth:1;
+ unsigned int proximity:1;
+ unsigned int temperature:1;
+ unsigned int city:1;
+ unsigned int state:1;
+ unsigned int facility:1;
+ unsigned int cc:1;
+ unsigned int cross_road:1;
+ unsigned int addr:1;
+} garmin_fs_flags_t;
+
+typedef struct garmin_fs_s
+{
+ format_specific_data fs;
+ garmin_fs_flags_t flags;
+
+ int protocol; /* ... used by device (-1 is MapSource) */
+
+ gbint32 icon;
+ int wpt_class;
+ gbint32 display;
+ gbint16 category;
+ double depth; /* depth in meters */
+ double proximity; /* proximity distance in meters */
+ double temperature;
+ char *city; /* city name */
+ char *facility; /* facility name */
+ char *state; /* state */
+ char *cc; /* country code */
+ char *cross_road; /* Intersection road label */
+ char *addr; /* address + number */
+ garmin_ilink_t *ilinks;
+} garmin_fs_t, *garmin_fs_p;
+
+garmin_fs_t *garmin_fs_alloc(const int protocol);
+void garmin_fs_destroy(void *fs);
+void garmin_fs_copy(garmin_fs_t **dest, garmin_fs_t *src);
+char *garmin_fs_xstrdup(const char *src, size_t size);
+
+/* for GPX */
+void garmin_fs_xml_convert(const int base_tag, int tag, const char *cdatastr, waypoint *waypt);
+void garmin_fs_xml_fprint(FILE *ofd, const waypoint *waypt);
+
+/* common garmin_fs utilities */
+
+/* ..convert_category: returns 1=OK; 0=Unable to convert category */
+unsigned char garmin_fs_convert_category(const char *category_name, gbuint16 *category);
+
+/* ..merge_category: returns 1=OK; 0=Unable to convert category */
+unsigned char garmin_fs_merge_category(const char *category_name, waypoint *waypt);
+
+#define GMSD_SECTION_CATEGORIES "Garmin Categories"
+
+#endif